<html>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<head>
<title>Section 16.1.&nbsp; Building a Blog</title>
<link rel="STYLESHEET" type="text/css" href="images/style.css">
<link rel="STYLESHEET" type="text/css" href="images/docsafari.css">
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-16.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-16-SECT-2.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
<br><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><TD valign="top"><a name="learnphpmysql-CHP-16-SECT-1"></a>
<h3 id="title-IDAFZCAJ" class="docSection1Title">16.1. Building a Blog</h3>
<p class="docText">A <span class="docEmphasis">blog</span><a name="IDX-CHP-16-0681"></a> 
 is short for weblog. It's an improvement on the simple guestbook/forums that started appearing on web sites years ago. They're now advanced enough to create mini-communities of people with similar interests or simply a place to post your rants about daily living. Blogs have been in the media as well. As Jeff Jarvis said in Buzz Machine, "...just as the raw voice of blogs makes newspeople uncomfortable. It's the sound of the future." Some blog examples are:</p>
<ul><li><p class="docList"><a class="docLink" target="_blank" href="http://www.americablog.org/">http://www.americablog.org/</a></p></li><li><p class="docList"><a class="docLink" target="_blank" href="http://mark-watson.blogspot.com/2005/02/pushing-java-back-into-background-for.html">http://mark-watson.blogspot.com/2005/02/pushing-java-back-into-background-for.html</a></p></li><li><p class="docList"><a class="docLink" target="_blank" href="http://www.doctorpundit.com">http://www.doctorpundit.com</a></p></LI></ul>
<p class="docText">As you can see from these three blog examples, one is political, one is about Mark Watson's life, and the third is a hodgepodge of RSS news feeds and personal podcasts. Of course, we've been given permission to use these blogs as examples, but go ahead and type in <tt>blogs</tt> in Google, and a million hits display. Weblogs are a huge trend; there are sites such as <a class="docLink" target="_blank" href="http://www.blogclicker.com/">http://www.blogclicker.com/</a> where you can register your blog and drive more traffic to it, or <a class="docLink" target="_blank" href="http://www.blogarama.com/">http://www.blogarama.com/</a>, which is a blog search engine. The market is hot for these online diaries, or diatribes!</p>
<p class="docText">There are several things you need to do when you establish a blog:</P>
<UL><li><p class="docList">Register users</P></li><li><p class="docList">View and post articles</p></LI><li><p class="docList">Categorize posts</P></li><li><p class="docList">Make comments to existing posts</P></LI><li><p class="docList">Archive posts</P></li></ul>
<p class="docText">All of these pages should be fairly configurable. If you decide to change the name of your blog, it won't be difficult to do.</P>
<a name="learnphpmysql-CHP-16-SECT-1.1"></a>
<H4 id="title-IDAN1CAJ" class="docSection2Title">16.1.1. Configuration File</h4>
<a name="IDX-CHP-16-0682"></a> 
<a name="IDX-CHP-16-0683"></a> 
<a name="IDX-CHP-16-0684"></a> 

<p class="docText">We'll create a common configuration file<a name="IDX-CHP-16-0685"></a> 
 called <span class="docEmphasis">config.php</span> to define where files are located, the name of the blog, and other basic configuration parameters. This is similar to the way you store your database connection information in the <span class="docEmphasis">db_login.php</span> file.</p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-1">Example 16-1</a> shows what it looks like.</p>
<a name="learnphpmysql-CHP-16-EX-1"></a><h5 id="title-IDAT2CAJ" class="docExampleTitle">Example 16-1. The config.php script defines settings that are used throughout the site</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
&lt;?php
  // put full path to Smarty.class.php
  require('/usr/share/php/Smarty/Smarty.class.php');
  $smarty = new Smarty();

  <span class="docEmphStrong">$smarty-&gt;template_dir = '/home/www/htmlkb/smarty/templates';</span>
  $smarty-&gt;compile_dir = '/home/www/htmlkb/smarty/templates_c';
  $smarty-&gt;cache_dir = '/home/www/htmlkb/smarty/cache';
  $smarty-&gt;config_dir = '/home/www/htmlkb/smarty/configs';

  $blog_title="Coffee Talk Blog";
?&gt;
</pre><br>

</TD></TR></table></p>
<p class="docText">We use <span class="docEmphasis">/home/www/htmlkb/smarty</span> as our path to the template engine files, but your path will be different based on where you installed Smarty. Note that all the template files go into the directory that <tt>$smart-&gt;template_dir</tt> points to. We also set the name of the blog to "Coffee Talk Blog."</P>

<a name="learnphpmysql-CHP-16-SECT-1.2"></a>
<h4 id="title-IDAJ3CAJ" class="docSection2Title">16.1.2. Page Framework</h4>
<p class="docText">We're going to use templates, which you learned about earlier, to help us build pages consistent in their appearance that are easy to modify. Let's start by setting up header and footer templates to include at the top and bottom of our pages using Smarty.</p>
<p class="docText">Again, these files must go into the directory defined in <span class="docEmphasis">config.php</span>, which isn't the same directory that the PHP files reside in. In our case, it's <span class="docEmphasis">/home/www/htmlkb/smarty/templates</span>, shown in <a class="docLink" href="#learnphpmysql-CHP-16-EX-2">Example 16-2</a>.</p>
<a name="learnphpmysql-CHP-16-EX-2"></a><h5 id="title-IDA33CAJ" class="docExampleTitle">Example 16-2. The header.tpl file</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{$blog_title}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Welcome to the {$blog_title}&lt;/h1&gt;
</pre><br>

</td></tr></table></P>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-2">Example 16-2</a> uses the <tt>$blog_title</tt> variable that was set up in the <span class="docEmphasis">config.php</span> script. This way, the blog name appears on every page automatically.</p>
<p class="docText">The footer shown in <a class="docLink" href="#learnphpmysql-CHP-16-EX-3">Example 16-3</a> is very basic, providing a couple of navigation links, but we can add more to it later.</p>
<a name="learnphpmysql-CHP-16-EX-3"></a><H5 id="title-IDAZ4CAJ" class="docExampleTitle">Example 16-3. The footer.tpl file</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
&lt;hr&gt;
&lt;a href='posts.php'&gt;Home&lt;/a&gt; || &lt;a href='logout.php'&gt;Logout&lt;/a&gt;
&lt;/head&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><br>

</td></TR></table></p>
<p class="docText">We'll add the code to include the header and footer shortly.</P>
<p class="docText">Our starting page provides the user with a way to log in. We'll use the PEAR <tt>Auth_HTTP</tt> package to authenticate users. This package is configured to work directly with the <tt>users</tt> table. Don't worry if you don't have the <tt>users</tt> table in your database now; we'll go through the code to create it and the other tables that we'll use in the examples.</p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-4">Example 16-4</a> shows you how to use Smarty and <tt>Auth_HTTP</tt> to build a flexible login page.</p>
<a name="learnphpmysql-CHP-16-EX-4"></a><H5 id="title-IDAW5CAJ" class="docExampleTitle">Example 16-4. The login script, called login.php</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
1 &lt;?php
2 // Example of Auth_HTTP the also returns additional information about the user
3 require_once('config.php');
4 require_once('db_login.php');
5 require_once("Auth/HTTP.php");
6 // We use the same connection string as the pear DB functions
7 $AuthOptions = array(
8 'dsn'=&gt;"mysql://$db_username:$db_password@$db_host/$db_database",
9 'table'=&gt;"users", // your table name
10 'usernamecol'=&gt;"username", // the table username column
11 'passwordcol'=&gt;"password", // the table password column
12 'cryptType'=&gt;"md5", // password encryption type in your db
13 'db_fields'=&gt;"*" // enabling fetch for other db columns
14 );
15 $authenticate = new Auth_HTTP("DB", $AuthOptions);
16 // set the realm name
17 $authenticate-&gt;setRealm('Member Area');
18 // authentication failed error message
19 $authenticate-&gt;setCancelText('&lt;h2&gt;Access Denied&lt;/h2&gt;');
20 // request authentication
21 $authenticate-&gt;start();
22 // compare username and password to stored values
23 if ($authenticate-&gt;getAuth()) {
24 session_start();
25 $smarty-&gt;assign('blog_title',$blog_title);
26 $smarty-&gt;display('header.tpl');
27 //setup session variable
28 $SESSION['username'] = $authenticate-&gt;username;
29 $SESSION['first_name'] = $authenticate-&gt;getAuthData('first_name');
30 $SESSION['last_name'] = $authenticate-&gt;getAuthData('last_name');
31 $SESSION['user_id'] = $authenticate-&gt;getAuthData('user_id');
32 echo "Login successful. Great to see you back ";
33 echo $authenticate-&gt;getAuthData('first_name');
34 echo " ";
35 echo $authenticate-&gt;getAuthData('last_name').".&lt;br /&gt;";
36 $smarty-&gt;display('footer.tpl');
37 }
38 ?&gt;
</pre><br>

</TD></TR></table></p>
<p class="docText">Since there are quite a few lines of code in this example, we'll discuss major points in the code by referencing their line numbers.</p>
<p class="docText">There are several lines devoted to including code and configuration details. Line 3 includes our blog configuration file. Line 4 includes the information required to log into the database. Line 5 includes the PEAR <tt>Auth_HTTP</tt> code.</p>
<p class="docText">To authenticate, we set up an array of options to tell <tt>Auth_HTTP</tt> how our database table stores the login information. Lines 7 through 14 set up that array. Lines 15 through 21 launch the authentication process. If it's successful, we start a session and store everything we know from the <tt>users</tt> table in the session so that it's available for easy access if we need it. Finally, we print out a message to welcome back the user with the user's full name.</p>
<p class="docText">If the user isn't logged in, she'll see a login prompt like the one in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-1">Figure 16-1</a>.</P>
<a name="learnphpmysql-CHP-16-FIG-1"></a><p><center>
<H5 class="docFigureTitle">Figure 16-1. The login dialog</h5>
<img border="0" alt="" width="531" height="244" SRC="images/learnphpmysql_1601.jpg">
</center></p><BR>
<p class="docText">After entering valid login credentials, the user will see <a class="docLink" href="#learnphpmysql-CHP-16-FIG-2">Figure 16-2</a>.</P>
<a name="learnphpmysql-CHP-16-FIG-2"></a><p><center>
<H5 class="docFigureTitle">Figure 16-2. We're logged in now</h5>
<img border="0" alt="" width="549" height="173" SRC="images/learnphpmysql_1602.jpg">
</center></p><br>
<p class="docText">If the user cancels the authentication dialog, she'll get a page displaying "Access Denied." All subsequent pages in the examples check the <tt>$username</tt> from the session to make sure that a user is logged in. If the user isn't logged in, a message displays pointing her back to the login page defined in <a class="docLink" href="#learnphpmysql-CHP-16-EX-4">Example 16-4</a>. That redirection page looks like <a class="docLink" href="#learnphpmysql-CHP-16-FIG-3">Figure 16-3</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-3"></a><p><center>
<h5 class="docFigureTitle">Figure 16-3. The login link directs the user back to the login.php script</h5>
<img border="0" alt="" width="549" height="173" SRC="images/learnphpmysql_1603.jpg">
</center></p><br>
<p class="docText">Now that we've taken care of logging in users, let's take another look at the database that supports our application.</p>

<a name="learnphpmysql-CHP-16-SECT-1.3"></a>
<h4 id="title-IDAWCDAJ" class="docSection2Title">16.1.3. Database</h4>
<a name="IDX-CHP-16-0686"></a> 

<p class="docText">We already created a <tt>users</tt> table for our bookstore examples. We'll add another user to that table to help us demonstrate ownership of postings and commentsspecifically, how we can modify them. We'll then have three new tables for our blog:<a name="IDX-CHP-16-0687"></a> 
 a table to store the categories, a table to store the posts, and a table to store the comments. We'll be using natural joins in our <tt>SELECT</tt> statements, since the key fields share the same names between related tables.</P>
<p><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><tr><TD><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><TR><td width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></TD><td valign="top">
<p class="docText">You should be careful that you do your natural joins in the right order, since changing the order can cause unexpected results; most notably, there will be result sets that have extra sets of rows.</p>
</td></TR></table></td></TR></table></p><br>
<p class="docText">You can create these through the GUI web client, <tt><B>phpMyAdmin</b></tt>. We're including the scripts to create them from the <tt>mysql</tt> command-line tool in <a class="docLink" href="#learnphpmysql-CHP-16-EX-5">Example 16-5</a>.</P>
<a name="learnphpmysql-CHP-16-EX-5"></a><h5 id="title-IDAAEDAJ" class="docExampleTitle">Example 16-5. SQL to create the posts table</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><TD>

<pre>
CREATE TABLE `posts` (
  `post_id` int(11) NOT NULL auto_increment,
  `category_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `title` varchar(150) NOT NULL,
  `body` text NOT NULL,
  `posted` timestamp,
  PRIMARY KEY  (`post_id`)
);
</pre><BR>

</td></tr></table></p>
<p class="docText">This returns the following information:</p>
<pre>
Query OK, 0 rows affected (0.02 sec)
</pre><BR>

<p class="docText">This table holds the contents of the post in the <tt>body</tt> field. The other fields link to attributes such as the poster and category. Use the code in <a class="docLink" href="#learnphpmysql-CHP-16-EX-6">Example 16-6</a> to create the <tt>categories</tt> table.</p>
<a name="learnphpmysql-CHP-16-EX-6"></a><H5 id="title-IDAZEDAJ" class="docExampleTitle">Example 16-6. SQL to create the categories table</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><TD>

<pre>
CREATE TABLE `categories` (
  `category_id` int(11) NOT NULL auto_increment,
  `category` varchar(150) NOT NULL,
  PRIMARY KEY  (`category_id`)
);
</pre><br>

</TD></tr></table></p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-6">Example 16-6</a> returns:</p>
<pre>
Query OK, 0 rows affected (0.01 sec)
</pre><br>

<p class="docText">The table created in <a class="docLink" href="#learnphpmysql-CHP-16-EX-7">Example 16-7</a> holds the categories that postings are posted to.</p>
<a name="learnphpmysql-CHP-16-EX-7"></a><h5 id="title-IDATFDAJ" class="docExampleTitle">Example 16-7. SQL to create the comments table</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
CREATE TABLE `comments` (
  `comment_id` int(11) NOT NULL auto_increment,
  `user_id` int(11) NOT NULL,
  `post_id` int(11) NOT NULL,
  `title` varchar(150) NOT NULL,
  `body` text NOT NULL,
  `posted` timestamp,
  PRIMARY KEY  (`comment_id`)
);
</pre><br>

</td></TR></table></p>
<p class="docText">This code returns the value that the query was OK:</p>
<pre>
Query OK, 0 rows affected (0.02 sec)
</pre><BR>

<p class="docText">The <tt>users</tt> table was created for our bookstore examples earlier, but we'll include it here, as <a class="docLink" href="#learnphpmysql-CHP-16-EX-8">Example 16-8</a>, just in case you're starting fresh.</P>
<a name="learnphpmysql-CHP-16-EX-8"></a><h5 id="title-IDAKGDAJ" class="docExampleTitle">Example 16-8. SQL to create the users table (may have already been created)</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
CREATE TABLE `users` (
  `user_id` int(11) NOT NULL auto_increment,
  `first_name` varchar(100) NOT NULL,
  `last_name` varchar(100) NOT NULL,
  `username` varchar(45) NOT NULL,
  `password` varchar(32) NOT NULL,
  PRIMARY KEY  (`user_id`));
</pre><BR>

</td></TR></table></p>
<p class="docText">SQL code returns, again, that the query value was OK:</p>
<pre>
Query OK, 0 rows affected (0.02 sec)
</pre><BR>

<a name="learnphpmysql-CHP-16-SECT-1.3.1"></a>
<H5 id="title-IDAXGDAJ" class="docSection3Title">16.1.3.1. Sample data</h5>
<p class="docText">To keep thing simple, we're going to insert some test data, using <a class="docLink" href="#learnphpmysql-CHP-16-EX-9">Example 16-9</a>. The test data lets us build pages to display posts and immediately see them displayed without having to build pages that add entries for them. Once we display posts, we'll code the pages to add posts and modify them. This same process is used for comments.</P>
<a name="learnphpmysql-CHP-16-EX-9"></a><h5 id="title-IDAFHDAJ" class="docExampleTitle">Example 16-9. Inserting sample data for the tables</h5><P><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
INSERT INTO categories VALUES (1,'Press Releases');
INSERT INTO categories VALUES (2,'Feature Requests');

INSERT INTO posts VALUES (NULL,1,1,'PHP Version 12','PHP Version 12, to be
released third quarter 2006. Featuring the artificial inteligence engine that
writes the code for you.',NULL);
INSERT INTO posts VALUES (NULL,1,1,'MySQL Version 8','Returns winning lotto
number.',NULL);
INSERT INTO posts VALUES (NULL,2,2,'Money Conversion',' Please add functions
for converting between foreign currentcies. ',NULL);

INSERT INTO comments VALUES (NULL,1,1,'Correction','Release delayed till the
year 2099',NULL);

INSERT INTO users VALUES (NULL,'Michele','Davis','mdavis',md5('secret'));
INSERT INTO users VALUES (NULL,'Jon','Phillips','jphillips',md5('password'));
</pre><br>

</td></tr></table></P>
<p class="docText">You should see a result similar to the one below for each of the <tt>INSERT</tt> SQL commands.</p>
<pre>
Query OK, 1 row affected, 1 warning (0.03 sec)
</pre><BR>

<p class="docText">We now have some sample data loaded; therefore, we can start writing some pages that display data.</p>


<a name="learnphpmysql-CHP-16-SECT-1.4"></a>
<h4 id="title-IDAZHDAJ" class="docSection2Title">16.1.4. Displaying a Postings Summary</H4>
<a name="IDX-CHP-16-0688"></a> 

<p class="docText">If you're not sure how to do something in the template beyond the objects we created, visit the online documentation for Smarty templates at <a class="docLink" target="_blank" href="http://smarty.php.net">http://smarty.php.net</a>. The templates separate the look and feel of the pages from the code that populates their data. While using the templates requires a little more work to set up and figure out the syntax, it reduces the overall amount of code you need to write. Smarty knows how to automate mundane tasks such as generating drop-down lists when building forms.</P>
<p class="docText">We're going to go right ahead and jump into building the main display page that works in tandem with its template, shown in <a class="docLink" href="#learnphpmysql-CHP-16-EX-10">Example 16-10</a>. Be sure to place the template files in the same directory that's established in your <span class="docEmphasis">config.php</span> file; the PHP files can go anywhere you like as long as they're web accessible.</p>
<a name="learnphpmysql-CHP-16-EX-10"></a><H5 id="title-IDAZIDAJ" class="docExampleTitle">Example 16-10. The posts.php script displays a listing of posts and their subjects</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
1 &lt;?php
2 session_start();
3 require_once('config.php');
4 require_once('db_login.php');
5 require_once("DB.php");
6 // Display the page header
7 $smarty-&gt;assign('blog_title',$blog_title);
8 $smarty-&gt;display('header.tpl');
9 // Check for valid login
10 if (!isset($_SESSION['username'])) {
11 echo 'Please &lt;a href="login.php"&gt;login&lt;/a&gt;.';
12 exit;
13 }
14 // Connect to the database
15 $connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database");
16
17 if (DB::isError($connection)){
18 die ("Could not connect to the database: &lt;br /&gt;". DB::errorMessage($connection));
19 }
20 // Query the posts with catagories and user information
21 $query = "SELECT * FROM `users` NATURAL JOIN `posts` NATURAL JOIN `categories`
22 ORDER BY `posted` DESC";
23 // Execute the database query
24 $result = $connection-&gt;query($query);
25 if (DB::isError($result)){
26 die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
27 }
28 // Place the query results into an array
29 while ($result_row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC)) {
30 $test[] = $result_row;
31 }
32 // Send the data to the template
33 $smarty-&gt;assign('posts', $test);
34 // Display the template with the data plugged in
35 $smarty-&gt;display('posts.tpl');
36 // Close the database connection
37 $connection-&gt;disconnect();
38 // Display the page footer
39 $smarty-&gt;display('footer.tpl');
40 ?&gt;
</pre><br>

</td></tr></table></p>
<p class="docText">Since <a class="docLink" href="#learnphpmysql-CHP-16-EX-10">Example 16-10</a> is a longer example, we'll break down what's happening line by line. Line 2 starts the session so we can check whether the user is logged in. Lines 7 and 8 display the header. Lines 10 through 13 check the <tt>$username_id</tt> session variable and display a login link if a user is not logged in. The rest of the page doesn't display because we use the <tt>exit</tt> command.</p>
<p class="docText">We're now ready to interact with the database. Lines 15 through 19 connect to the database and check for connection errors. Line 21 defines the query that we'll use to get all of the information about the postings. We have to be very careful with the order of the natural joins or we'll end up getting results that aren't properly linked together. The <tt>users</tt> table is referenced first. We also define an <tt>ORDER BY</tt> statement because we want the most recent postings displayed first. Lines 29 through 31 assign the query results to an array that we'll assign to the <tt>smarty</tt> template in line 33.</p>
<p class="docText">Now that we have all of the information from the database, we display the template in line 35. The template is defined below in <a class="docLink" href="#learnphpmysql-CHP-16-EX-11">Example 16-11</a>. The last line of the template provides a link for users to add postings. Line 39 displays the footer.</p>
<a name="learnphpmysql-CHP-16-EX-11"></a><h5 id="title-IDA5JDAJ" class="docExampleTitle">Example 16-11. The posts.tpl template file defines how the postings appear on the page</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><TD>

<pre>
{section name=mysec loop=$posts}
<B>&lt;a href="view_post.php?post_id={$posts[mysec].post_id}"&gt;</b>{$posts[mysec].title}&lt;/a&gt;
by &lt;b&gt;{$posts[mysec].first_name} {$posts[mysec].last_name}&lt;/b&gt;
from the &lt;b&gt;{$posts[mysec].category}&lt;/b&gt; category at &lt;b&gt;{$posts[mysec].posted}&lt;/b&gt;.
&lt;br /&gt;
<span class="docEmphStrong">{/section}</span>
&lt;br /&gt;
Click to &lt;a href="modify_post.php?action=add"&gt;add&lt;/a&gt; a posting.&lt;br /&gt;
</pre><br>

</TD></tr></table></p>
<p class="docText">Because there may be numerous postings to display using the same format, we define a section in the template that'll go through the <tt>$posts</tt> array and substitute the values for the chunk of HTML enclosed in the section tags. To do the same thing outside of Smarty, we'd have to use a <tt>for</tt> or a <tt>while</tt> loop to iterate through the posts in the array and display them one by one.</p>
<P><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><tr><TD><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><tr><td width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></TD><TD valign="top">
<p class="docText">Notice that the links that display the posting with its body on a separate page are generated with an embedded link in the template.</p>
</TD></tr></table></td></TR></table></P><br>
<p class="docText">The <span class="docEmphasis">view_post.php</span> script uses the <tt>post_id</tt> value in the link to determine which posting to display. All of the pieces must work together for our pages to function correctly.</p>
<p class="docText">The sample data we loaded causes a page that looks like <a class="docLink" href="#learnphpmysql-CHP-16-FIG-4">Figure 16-4</a> to display when we request the <span class="docEmphasis">posts.php</span> page, and then the template populates.</p>
<a name="learnphpmysql-CHP-16-FIG-4"></a><p><center>
<H5 class="docFigureTitle">Figure 16-4. The summary of postings</h5>
<img border="0" alt="" width="549" height="201" SRC="images/learnphpmysql_1604.jpg">
</center></P><br>
<p class="docText">As you can see in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-4">Figure 16-4</a>, we've got a list of postings. We've also provided a couple of links. The link that is the title of a posting sends us to a posting detail and comments page. The link that displays after the list of postings points us to a page for adding posts. These two links are actually processed by the same script, since the process for adding a posting is similar to the process for updating a posting.</p>

<a name="learnphpmysql-CHP-16-SECT-1.5"></a>
<H4 id="title-IDAFMDAJ" class="docSection2Title">16.1.5. Displaying a Posting and Its Comments</H4>
<a name="IDX-CHP-16-0689"></a> 

<p class="docText">To create the <span class="docEmphasis">view_post.php</span> script, we'll reuse some of the code and add a bit in <a class="docLink" href="#learnphpmysql-CHP-16-EX-12">Example 16-12</a>. The script takes a <tt>post_id</tt> as a <tt>GET</tt> parameter and displays the posting, including its body. Comments for the posting are also listed. The user who creates the posting can delete or modify it. Likewise, users can delete or modify any comment entries they have made.</p>
<a name="learnphpmysql-CHP-16-EX-12"></a><H5 id="title-IDA5MDAJ" class="docExampleTitle">Example 16-12. The view_post.php script displays a summary of its comments</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;?php

session_start();

require_once('config.php');
require_once('db_login.php');
require_once("DB.php");

// Display the header
$smarty-&gt;assign('blog_title',$blog_title);
$smarty-&gt;display('header.tpl');

// Check for valid login
if (!isset($_SESSION["username"])) {
echo 'Please &lt;a href="login.php"&gt;login&lt;/a&gt;.';
exit;
}

// Connect to the database
$connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database");

if (DB::isError($connection)){
die ("Could not connect to the database: &lt;br /&gt;". DB::errorMessage($connection));
}

$post_id = $_GET["post_id"];

$query = "SELECT * FROM `users` NATURAL JOIN `posts` NATURAL JOIN `categories`
<span class="docEmphStrong">WHERE `post_id`=$post_id";</span>
$result = $connection-&gt;query($query);

if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}

while ($result_row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC)) {
$test[]=$result_row;
}

$smarty-&gt;assign('posts',$test);
<span class="docEmphStrong">$smarty-&gt;assign('owner_id',$_SESSION["user_id"]);</span>
<span class="docEmphStrong">$query = "SELECT * FROM `users` NATURAL JOIN `comments` WHERE `post_id`=$post_id";</span>
<span class="docEmphStrong">$result = $connection-&gt;query($query);</span>

if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}

<span class="docEmphStrong">$comment_count = $result-&gt;numRows();</span>

<span class="docEmphStrong">while ($result_row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC)) {</span>
<span class="docEmphStrong">$comments[] = $result_row;</span>
<span class="docEmphStrong">}</span>

<span class="docEmphStrong">$smarty-&gt;assign('posts',$test);</span>
<span class="docEmphStrong">$smarty-&gt;assign('comments',$comments);</span>
<span class="docEmphStrong">$smarty-&gt;assign('comment_count',$comment_count);</span>

<span class="docEmphStrong">$smarty-&gt;display('view_post.tpl');</span>

$connection-&gt;disconnect();

// Display the footer
$smarty-&gt;display('footer.tpl');

?&gt;
</pre><br>

</td></tr></table></p>
<p class="docText">The code in <a class="docLink" href="#learnphpmysql-CHP-16-EX-12">Example 16-12</a> starts out like the code in <a class="docLink" href="#learnphpmysql-CHP-16-EX-10">Example 16-10</a>, since they both query and display postings. The difference is that the query string uses the <tt>post_id</tt> parameter in the <tt>WHERE</tt> clause to only retrieve information for one posting.</p>
<p class="docText">The second half of the code queries the <tt>comments</tt> table, also using the <tt>post_id</tt> in the <tt>WHERE</tt> clause to retrieve only comments for the posting that we're displaying. We run into two complications though. Any given posting may or may not have any comments associated with it, and we'd like to display a heading before we list the comments. However, if there are no comments, we don't want to display that heading.</p>
<p class="docText">To assign the variable <tt>$comment_count</tt>, we use:</p>
<pre>
$comment_count=$result-&gt;numRows();
</pre><br>

<p class="docText">The template will then be able to tell if there are any comments. The other problem is that we want to provide links for editing and deleting posts as well as comments, only if the logged-in user created the posting or comment. This means we need to send in the current user's ID to the template before calling it. We send in the <tt>user_id</tt> form to the session template like this:</P>
<pre>
$smarty-&gt;assign('owner_id',$_SESSION[user_id]);
</pre><br>

<p class="docText">When the template displays, it has the data from the posting, the comments, how many comments, and the currently logged-in user's ID.</p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-13">Example 16-13</a> lists the contents of the <span class="docEmphasis">view_post.tpl</span> template used in the <span class="docEmphasis">view_posts.php</span> file.</P>
<a name="learnphpmysql-CHP-16-EX-13"></a><H5 id="title-IDARQDAJ" class="docExampleTitle">Example 16-13. view_post.tpl</h5><P><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
{section name=mysec loop=$posts}
&lt;h2&gt;{$posts[mysec].title}&lt;/h2&gt;
{$posts[mysec].body}
&lt;br /&gt;
Posted by &lt;b&gt;{$posts[mysec].first_name} {$posts[mysec].last_name}&lt;/b&gt;
from the &lt;b&gt;{$posts[mysec].category}&lt;/b&gt; category at
&lt;b&gt;{$posts[mysec].posted}&lt;/b&gt;.&lt;br /&gt;
<span class="docEmphStrong">{if $posts[mysec].user_id == $owner_id}</span>
&lt;a href="modify_post.php?post_id={$posts[mysec].post_id}&amp;action=edit"&gt;Edit&lt;/a&gt; ||
&lt;a href="modify_post.php?post_id={$posts[mysec].post_id}&amp;action=delete"&gt;Delete&lt;/a&gt; ||
&lt;a href="modify_comment.php?post_id={$posts[mysec].post_id}&amp;action=add"
&gt;Add a comment&lt;/a&gt;
&lt;br /&gt;
<span class="docEmphStrong">{/if}</span>
<span class="docEmphStrong">{/section}</span>
<span class="docEmphStrong">{if $comment_count != "0"}</span>
&lt;h3&gt;Comments&lt;/h3&gt;
<span class="docEmphStrong">{section name=mysec2 loop=$comments}</span>
&lt;hr /&gt;
&lt;b&gt;{$comments[mysec2].title}&lt;/b&gt;
&lt;br /&gt;
{$comments[mysec2].body}
&lt;br /&gt;
Posted by &lt;b&gt;{$comments[mysec2].first_name} {$comments[mysec2].last_name}&lt;/b&gt;
at &lt;b&gt;{$comments[mysec2].posted}&lt;/b&gt;.&lt;br /&gt;
<span class="docEmphStrong">{if $comments[mysec2].user_id == $owner_id}</span>
&lt;a href="modify_comment.php?comment_id={$comments[mysec2].comment_id}&amp;action=edit"
&gt;Edit&lt;/a&gt; ||
&lt;a href="modify_comment.php?comment_id={$comments[mysec2].comment_id}&amp;action=delete"
&gt;Delete&lt;/a&gt;
&lt;br /&gt;
<span class="docEmphStrong">{/if}</span>
<span class="docEmphStrong">{/section}</span>
{/if}
</pre><br>

</TD></tr></table></P>
<p class="docText">This template builds on the template from <a class="docLink" href="#learnphpmysql-CHP-16-EX-11">Example 16-11</a> by forming another repeatable section for comments. We use the Smarty <tt>{if }</tt> evaluation to test for the presence of comments and to see whether the current user is also the creator of posts and comments. If the number of comments is 0, we don't display a heading for the comments. If the user's ID and the <tt>user_id</tt> from the posting or comment match, then we display the links for editing or modifying them, as shown in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-5">Figure 16-5</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-5"></a><p><center>
<H5 class="docFigureTitle">Figure 16-5. Our posting is displayed with its comments</H5>
<img border="0" alt="" width="549" height="285" SRC="images/learnphpmysql_1605.jpg">
</center></p><BR>
<p class="docText">Adding and deleting posts are handled, so we'll move on to doing the most advanced script yet, which can handle adding and changing posts.</p>

<a name="learnphpmysql-CHP-16-SECT-1.6"></a>
<h4 id="title-IDA1SDAJ" class="docSection2Title">16.1.6. Adding and Changing Posts</H4>
<a name="IDX-CHP-16-0690"></a> 

<p class="docText">The adding and changing functionalities are grouped together, because they both build the same HTML form to add or modify the posting, as well as the validation steps before saving to the database. Again, we're building on the concept of using the same script to generate an HTML form and process its submission.</P>
<p class="docText">There are quite a few things going on in this script:</p>
<ul><li><p class="docList">In lines 26 through 31, we connect to the database, since most of the operations require interaction with the database.</p></LI><li><p class="docList">In lines 18 through 23, we grab variables from the environment, since the script might be taking a <tt>post_id</tt> to tell which posting we're editing, and we get other variables from the <tt>POST</tt> from submissions that must be processed.</P></li><li><p class="docList">Lines 32 through 45 process a deletion if the <tt>$action</tt> variable is set to delete. The <tt>WHERE</tt> clause of the <tt>delete</tt> query includes both the <tt>$post_id</tt>, which was sent to the script and therefore may be forged. The <tt>$user_id</tt> validates that the logged-in user created the script. If someone sends in a <tt>post_id</tt> of a posting he doesn't own, he can't delete it. The <tt>$stop</tt> variable is set to stop any further processing, as this is an end point. Only the page footer is added.</P></LI><li><p class="docList">Lines 47 through 67 use the <tt>$post_id</tt> from the URL to grab post information from the database and prepopulate the form in the template with the existing data for the post. The <tt>$action</tt> variable is set to <tt>edit</tt> so <tt>modify_posts.php</tt> knows to process the data when the user submits the form after editing. The <tt>$stop</tt> variable is set to stop any further processing, as this is an end point. Only the page footer is added.</P></li><li><p class="docList">Line 70 checks whether the script ran from a form submission. If it did, then we're processing data for an add operation or an update. Then this data must be validated.</p></li><li><p class="docList">Lines 71 through 82 validate the data. If there's a problem, we tell the user exactly what the error is, and then redisplay the form using the code in lines 128 through 136 with the data the user sent in so that she don't have to start over. When the user resubmits her form, it checks again for correctness. Although the checks done here are just to make sure the fields aren't empty, they could be as complex as you desire and would go in the same place in the script.</p></li><li><p class="docList">Lines 84 through 96 process an add operation after there is successful validation. The query is built using the data from the form submission, and then it is executed. The <tt>$stop</tt> variable is set to stop any further processing, as this is an end point. Only the page footer is added.</p></li><li><p class="docList">Lines 97 through 112 process an update operation after successful validation. The query is built, and then executed. The <tt>$stop</tt> variable is set to stop any further processing, as this is an end point. Only the page footer will be added.</p></LI><li><p class="docList">Lines 114 through 126 display an empty form. This is the first step when adding a new posting.</p></LI></UL>
<p class="docText">Throughout the processing, we check that the value of the <tt>$stop</tt> variable skips processing remaining steps if an error is encountered or we simply have accomplished what needs to happen. All of the steps rely on the template to display the HTML form.</p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-16-EX-14">Example 16-14</a> lists the script.</P>
<a name="learnphpmysql-CHP-16-EX-14"></a><h5 id="title-IDA1VDAJ" class="docExampleTitle">Example 16-14. modify_posts.php</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
1 &lt;?php
2   include('db_login.php');
3   require_once( 'DB.php' );
4   require_once( 'config.php' );
5
6   //check for valid login
7   session_start();
8
9   //display the header
10   $smarty-&gt;assign('blog_title',$blog_title);
11   $smarty-&gt;display('header.tpl');
12
13   if  (!isset($_SESSION['username'])) {
14     echo ("Please &lt;a href='login.php'&gt;login&lt;/a&gt;.");
15     exit();
16   }
17   //grab submission variables
18   $post_id=$_POST[post_id];
19   $title=htmlentities($_POST['title']);
20   $body=htmlentities($_POST['body']);
21   $action=htmlentities($_POST['action']);
22   $category_id=htmlentities($_POST['category_id']);
23   $user_id=$_SESSION["user_id"];
24
25   //conected to database
26   $connection = DB::connect( "mysql://$db_username:$db_password@$db_
27 host/$db_database" );
28   if (!$connection)
29   {
30      die ("Could not connect to the database: &lt;br&gt;". DB::errorMessage());
31   };
32   if ($_GET['action']=="delete" and !$stop)
33   {
34     $post_id=$_GET[post_id];
35     $query = "delete from posts where post_id='".$post_id."' and
36 user_id='".$user_id."'";
37     $result = $connection-&gt;query($query);
38     if (DB::isError($result))
39     {
40       die ("Could not query the database: &lt;br&gt;". $query. " ".
41 DB::errorMessage($result));
42     };
43     echo ("Deleted successfully.&lt;br&gt;");
44     $stop="TRUE";
45   }
46
47   //we're editing an entry, explicitly grab the id from the URL
48   if ($_GET[post_id] AND !$stop) {
49     $query = "SELECT * FROM users NATURAL JOIN posts NATURAL JOIN categories
50 where post_id = $_GET[post_id]";
51     $result = $connection-&gt;query($query);
52     if (DB::isError($result))
53     {
54       die ("Could not query the database: &lt;br&gt;". $query. " ".
55 DB::errorMessage($result));
56     };
57     while ($result_row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC)) {
58     $posts[]=$result_row;
59     }
60     $smarty-&gt;assign('action','edit');
61     $smarty-&gt;assign('posts',$posts);
62     //get those categories
63     $query = "SELECT category_id, category FROM categories";
64     $smarty-&gt;assign('categories',$connection-&gt;getAssoc($query));
65     $smarty-&gt;display('post_form.tpl');
66     $stop="TRUE";
67   }
68
69   //The form was submitted, was it an add or an edit?
70   if ($_POST['submit'] AND !$stop)
71   {
72     //validate fields
73     if ($title == ""){
74       echo ("Title must not be null.&lt;br&gt;");
75       $found_error=TRUE;
76       $stop="TRUE";
77     }
78     if ($body == ""){
79       echo ("Body must not be null.&lt;br&gt;");
80       $found_error=TRUE;
81       $stop="TRUE";
82     }
83     //validated OK lets hit the databae
84     if ( $_POST['action']=="add" AND !$stop)
85{
86       $query = "insert into posts values (NULL,
87 "."'".$category_id."','".$user_id."','".$title."','".$body."', NULL)";
88       $result = $connection-&gt;query($query);
89       if (DB::isError($result))
90       {
91         die ("Could not query the database: &lt;br&gt;". $query. " ".
92 DB::errorMessage($result));
93       };
94       echo ("Posted successfully.&lt;br&gt;");
95       $stop="TRUE";
96     }
97     if ($_POST['action']=="edit" and !$stop)
98     {
99       //do nothing
100       $query = "update posts set category_id ='".$category_id."',
101 title ='".$title."',body='".$body."' where post_id='".$post_id."'
102 and user_id='".$user_id."'";
103       //echo $query;
104       $result = $connection-&gt;query($query);
105       if (DB::isError($result))
106       {
107         die ("Could not query the database: &lt;br&gt;". $query. " ".
108 DB::errorMessage($result));
109       };
110       echo ("Updated successfully.&lt;br&gt;");
111       $stop="TRUE";
112     }
113   }
114   if (!$stop)
115   {
116     //display blank form
117     //create an empty entry
118     $result_row=array('title'=&gt;NULL,'body'=&gt;NULL);
119     $posts[]=$result_row;
120     //get the categories
121     $query = "SELECT category_id, category FROM categories";
122     $smarty-&gt;assign('categories',$connection-&gt;getAssoc($query));
123     $smarty-&gt;assign('posts',$posts);
124     $smarty-&gt;assign('action','add');
125     $smarty-&gt;display('post_form.tpl');
126   }
127
128   if ($found_error) {
129     //assign old vals
130     //redisplay form
131     $result_row=array('title'=&gt;"$title",'body'=&gt;"$body",'post_id'=&gt;"$post_id");
132     $posts[]=$result_row;
133     $smarty-&gt;assign('action',$action);
134     $smarty-&gt;assign('posts',$posts);
135     $smarty-&gt;display('post_form.tpl');
136   }
137   //display the footer
138   $smarty-&gt;display('footer.tpl');
139
140 ?&gt;
</pre><BR>

</td></tr></table></P>
<p class="docText">The good news is that the template isn't very complicated! Its job is simply to take information from the user and hang onto a couple of hidden fields, <tt>action</tt> and <tt>post_id</tt>. They help the <span class="docEmphasis">post_form.php</span> script keep track of whether we're adding, updating, or deleting. If we're editing, then the <tt>post_id</tt> tells the script which article is being edited.</P>
<p class="docText">This example highlights the advantage of using a template. If you want to make simple changes to the wording or layout of the form, then modifying the template is done by a user that just knows HTML.</p>
<P><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><tr><td><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><TR><TD width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></td><td valign="top">
<p class="docText">The Smarty tags shouldn't be altered.</p>
</td></TR></table></td></TR></table></p><br>
<p class="docText">If the HTML code is peppered into the PHP code, as in <a class="docLink" href="#learnphpmysql-CHP-16-EX-14">Example 16-14</a>, users would probably break something when making modifications. You'll need the code for the templates, as shown in <a class="docLink" href="#learnphpmysql-CHP-16-EX-15">Example 16-15</a>.</P>
<a name="learnphpmysql-CHP-16-EX-15"></a><H5 id="title-IDAFXDAJ" class="docExampleTitle">Example 16-15. post_form.tpl</h5><P><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;form action="modify_post.php" method="POST"&gt;
&lt;label&gt;
Title: &lt;input type="text" name="title" value="{$posts[mysec].title}"&gt;
&lt;/label&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;label&gt;
Body: &lt;textarea name="body" cols="40" rows="4"&gt;{$posts[mysec].body}&lt;/textarea&gt;
&lt;/label&gt;
&lt;input type="hidden" name="action" value="{$action}"&gt;
&lt;input type="hidden" name="post_id" value="{$posts[mysec].post_id}"&gt;&lt;br&gt;
&lt;label&gt;
Category:
<span class="docEmphStrong">{html_options name="category_id" options=$categories</span>
<span class="docEmphStrong">selected=$posts[mysec].category_id}</span>
&lt;/label&gt;
&lt;br /&gt;
&lt;input type="submit" name="submit" value="Post" /&gt;
&lt;/form&gt;
{/section}
</pre><br>

</td></tr></table></p>
<p class="docText">The only thing new here is the <tt>{html_options}</tt> Smarty tag. This automates the generation of a drop-down selection list in the HTML form for the categories. Without Smarty, displaying a select element in a form requires using a <tt>for</tt> or <tt>while</tt> loop to display the elements; this can be very tedious, especially if you have a lot of selection lists.</p>
<p class="docText">Clicking on the Edit link for the first posting in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-5">Figure 16-5</a> causes a dialog to display, as in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-6">Figure 16-6</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-6"></a><p><center>
<h5 class="docFigureTitle">Figure 16-6. Editing the posting title PHP Version 12</h5>
<img border="0" alt="" width="549" height="268" SRC="images/learnphpmysql_1606.jpg">
</center></p><BR>
<p class="docText">Notice that the drop-down list defaults to the value we sent from the script. You can modify the entry, as shown in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-7">Figure 16-7</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-7"></a><p><center>
<H5 class="docFigureTitle">Figure 16-7. Adding text to a posting</H5>
<img border="0" alt="" width="549" height="268" SRC="images/learnphpmysql_1607.jpg">
</center></p><BR>
<p class="docText">After adding the text "It also contains a module for predicting the lottery," we click the <tt>Post</tt> button. <a class="docLink" href="#learnphpmysql-CHP-16-FIG-8">Figure 16-8</a> indicates that the posting updated successfully.</p>
<a name="learnphpmysql-CHP-16-FIG-8"></a><p><center>
<h5 class="docFigureTitle">Figure 16-8. The update was successful</H5>
<img border="0" alt="" width="549" height="197" SRC="images/learnphpmysql_1608.jpg">
</center></p><BR>
<p class="docText">Now we can navigate back to the article, shown in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-9">Figure 16-9</a>, by clicking on the <tt>Home</tt> link and selecting the <tt>PHP Version 12</tt> posting.</p>
<a name="learnphpmysql-CHP-16-FIG-9"></a><p><center>
<H5 class="docFigureTitle">Figure 16-9. The new text appears in the post</H5>
<img border="0" alt="" width="549" height="338" SRC="images/learnphpmysql_1609.jpg">
</center></p><BR>
<p class="docText">You can go ahead and try sending in an empty field. The code alerts you that you can't do that and sends you back to the HTML form to fix the problem.</p>

<a name="learnphpmysql-CHP-16-SECT-1.7"></a>
<h4 id="title-IDAB1DAJ" class="docSection2Title">16.1.7. Adding and Changing Comments</H4>
<a name="IDX-CHP-16-0691"></a> 

<p class="docText">The code for working with comments is nearly identical to the PHP code for modifying posts. The changes are emphasized in <a class="docLink" href="#learnphpmysql-CHP-16-EX-16">Example 16-16</a>.</P>
<a name="learnphpmysql-CHP-16-EX-16"></a><h5 id="title-IDAU1DAJ" class="docExampleTitle">Example 16-16. modify_comment.php</h5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><TD>

<pre>
&lt;?php

session_start();

require_once('config.php');
require_once('db_login.php');
require_once("DB.php");

// Display the header
$smarty-&gt;assign('blog_title',$blog_title);
$smarty-&gt;display('header.tpl');

// Check for valid login
if (!isset($_SESSION["username"])) {
echo 'Please &lt;a href="login.php"&gt;login&lt;/a&gt;.';
exit;
}

// Connect to the database
$connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database");

if (DB::isError($connection)){
die ("Could not connect to the database: &lt;br /&gt;". DB::errorMessage($connection));
}

$stop = false;

$post_id = $_REQUEST["post_id"];

$title = htmlentities($_POST['title']);
$body = htmlentities($_POST['body']);
$action = htmlentities($_POST['action']);
$category_id = htmlentities($_POST['category_id']);
$user_id = $_SESSION["user_id"];
<span class="docEmphStrong">$comment_id = htmlentities($_POST['comment_id']);</span>

if ($_GET['action'] == "delete" and !$stop) {
<span class="docEmphStrong">$comment_id = $_GET["comment_id"];</span>
<span class="docEmphStrong">$query = "DELETE FROM `comments` WHERE `comment_id`='".$comment_id."'</span>
<span class="docEmphStrong">AND `user_id`='".$user_id."'";</span>
$result = $connection-&gt;query($query);
if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}
echo "Deleted successfully.&lt;br /&gt;";
$stop = true;
}

// We're editing an entry, explicitly grab the id from the URL
<span class="docEmphStrong">if ($_GET["comment_id"] and !$stop) {</span>
<span class="docEmphStrong">$query = "SELECT * FROM `comments` NATURAL JOIN `users`</span>
<span class="docEmphStrong">WHERE `comment_id`=".$_GET["comment_id"];</span>
$result = $connection-&gt;query($query);
if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}
while ($result_row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC)) {
$comments[] = $result_row;
}
$post_id = $_GET["post_id"];
$smarty-&gt;assign('action','edit');
$smarty-&gt;assign('comments',$comments);
$smarty-&gt;assign('post_id',$post_id);
$smarty-&gt;display('comment_form.tpl');
// Display the footer
$smarty-&gt;display('footer.tpl');
exit;
}

//The form was submitted, was it an add or an update?
if ($_POST['submit'] and !$stop) {
// Validate fields
if ($title == ""){
echo 'Title must not be null.&lt;br /&gt;';
$found_error = true;
$stop = true;
}
if ($body == ""){
echo "Body must not be null.&lt;br /&gt;";
$found_error = true;
$stop = true;
}
// Validated OK lets hit the database
if ($_POST['action'] == "add" AND !$stop) {
<span class="docEmphStrong">$query = "INSERT INTO `comments` VALUES (NULL</span>,
<span class="docEmphStrong">'".$user_id."','".$post_id."','".$title."','".$body."', NULL)";</span>
$result = $connection-&gt;query($query);
if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}
echo "Posted successfully.&lt;br /&gt;";
$stop = true;
}
if ($_POST['action']=="edit" and !$stop){
<span class="docEmphStrong">$query = "UPDATE `comments` SET</span>
<span class="docEmphStrong">`title`='".$title."'</span>,
<span class="docEmphStrong">`body`='".$body."'</span>
<span class="docEmphStrong">WHERE `comment_id`='".$comment_id."' AND `user_id`='".$user_id."'";</span>
$result = $connection-&gt;query($query);
if (DB::isError($result)){
die("Could not query the database: &lt;br /&gt;".$query." ".DB::errorMessage($result));
}
echo 'Updated successfully.&lt;br /&gt;';
$stop = true;
}
}

if (!$stop){
// Display blank form
// Create an empty entry
$post_id = $_GET["post_id"];
$result_row = array('title'=&gt;NULL,'body'=&gt;NULL,'comment_id'=&gt;NULL);
$comments[] = $result_row;
// Get the categories
$smarty-&gt;assign('post_id',$post_id);
$smarty-&gt;assign('comments',$comments);
$smarty-&gt;assign('action','add');
$smarty-&gt;display('comment_form.tpl');
}

if ($found_error) {
// Assign old vals
// Redisplay form
$post_id = $_POST["post_id"];
$result_row = array('title'=&gt;"$title",'body'=&gt;"$body",'comment_id'=&gt;"$comment_id");
$comments[] = $result_row;
$smarty-&gt;assign('action',$action);
$smarty-&gt;assign('post_id',$post_id);
$smarty-&gt;assign('comments',$comments);
$smarty-&gt;display('comment_form.tpl');
}

// Display the footer
$smarty-&gt;display('footer.tpl');

?&gt;
</pre><br>

</TD></tr></table></p>
<p class="docText">The changes revolved around working with a <tt>comment_id</tt> instead of a <tt>post_id</tt> as the key value, although you still track the <tt>posting_id</tt> for new comments. The name of the template is <span class="docEmphasis">comment_form.tpl</span> instead of <span class="docEmphasis">post_form.tpl</span>.</P>
<p class="docText">The template for building the comments form, shown in <a class="docLink" href="#learnphpmysql-CHP-16-EX-17">Example 16-17</a>, is the same as the template for posts, except you no longer need the category selection drop-down list, and you've replaced <tt>posts</tt> with <tt>comments</tt> everywhere it appears in the templateexcept for the hidden form parameter <tt>post_id</tt> that is used for tracking, which is what posting a new comment is for.</P>
<a name="learnphpmysql-CHP-16-EX-17"></a><h5 id="title-IDAN4DAJ" class="docExampleTitle">Example 16-17. comment_form.tpl</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
{section name=mysec loop=$comments}
&lt;form action="modify_comment.php" method="post"&gt;
&lt;label&gt;
Title:
&lt;input type="text" name="title" value="{$comments[mysec].title}" /&gt;
&lt;/label&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;label&gt;
Body:
&lt;textarea name="body" cols="40" rows="4"&gt;{$comments[mysec].body}&lt;/textarea&gt;
&lt;/label&gt;
&lt;input type="hidden" name="action" value="{$action}" /&gt;
&lt;input type="hidden" name="post_id" value="{$post_id}" /&gt;
&lt;input type="hidden" name="comment_id" value="{$comments[mysec].comment_id}" /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;input type="submit" name="submit" value="Post" /&gt;
&lt;/form&gt;
{/section}
</pre><br>

</td></tr></table></p>
<p class="docText">Clicking on the edit link for the Correction comment displays <a class="docLink" href="#learnphpmysql-CHP-16-FIG-10">Figure 16-10</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-10"></a><p><center>
<h5 class="docFigureTitle">Figure 16-10. Updating the comment and adding some text</h5>
<img border="0" alt="" width="549" height="326" SRC="images/learnphpmysql_1610.jpg">
</center></p><BR>
<p class="docText">We add the text "Don't hold your breath!" and click Post, bringing us to the screen shown in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-11">Figure 16-11</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-11"></a><p><center>
<H5 class="docFigureTitle">Figure 16-11. Confirmation of the comment update</H5>
<img border="0" alt="" width="549" height="202" SRC="images/learnphpmysql_1611.jpg">
</center></p><BR>
<p class="docText">Finally, we navigate back to the post, in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-12">Figure 16-12</a>.</p>
<a name="learnphpmysql-CHP-16-FIG-12"></a><p><center>
<h5 class="docFigureTitle">Figure 16-12. The comment has been updated</H5>
<img border="0" alt="" width="549" height="400" SRC="images/learnphpmysql_1612.jpg">
</center></p><BR>
<p class="docText">We can see the comment has been updated in <a class="docLink" href="#learnphpmysql-CHP-16-FIG-12">Figure 16-12</a>. We can use the same format of PHP and template files to modify other entities in our database, such as categories or users. The possibilities are endless. You can embark on creating numerous dynamic web sites armed with your learning from this book.</p>
<p class="docText">The next (and last) chapter discusses resources for PHP and MySQL questions. There is a plethora of information out there, and it's available right at your fingertips!</p>


<a href="11011536.html"><img src="images/pixel.jpg" alt="" width="1" height="1" border="0"></a></TD></TR></table>
<br>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-16.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-16-SECT-2.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
<script type="text/javascript"><!--
google_ad_client = "pub-0203281046321155";
google_alternate_ad_url = "http://www.bookhtml.com/adbrite.htm";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="4867465545";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "0000FF";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</html>
